﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;

using ProfileManager.Helpers;
using ProfileManager.Properties;

namespace ProfileManager.DataAccess
{
    public class AccountInfo
    {
        public Guid Id { get; set; }
        public Guid ServiceInfoId { get; set; }
        public string Login { get; set; }
        public string Password { get; set; }
        public string Email { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string SecretQuestion { get; set; }
        public string SecretAnswer { get; set; }
        public string MobilePhone { get; set; }
        public string ShortId { get; set; }
        public string AdditionalInfo { get; set; }
        public DateTime DateCreated { get; set; }
        public bool Deleted { get; set; }

        public void Insert()
        {
            try
            {
                if (!IsExist())
                {
                    using (SqlConnection con = CommonDb.GetBaseConection())
                    {
                        Guid newId = Guid.NewGuid();

                        SqlCommand saveCmd = new SqlCommand("AccountInfoInsert", con);
                        saveCmd.CommandType = CommandType.StoredProcedure;

                        saveCmd.Parameters.Add("@Id", SqlDbType.UniqueIdentifier).Value = newId;
                        saveCmd.Parameters.Add("@ServiceInfoId", SqlDbType.UniqueIdentifier).Value = ServiceInfoId;
                        saveCmd.Parameters.Add("@Login", SqlDbType.VarBinary).Value = Crypto.Encrypt(Login);
                        saveCmd.Parameters.Add("@Password", SqlDbType.VarBinary).Value = Crypto.Encrypt(Password);
                        saveCmd.Parameters.Add("@Email", SqlDbType.VarBinary).Value = Crypto.Encrypt(Email);
                        saveCmd.Parameters.Add("@FirstName", SqlDbType.VarBinary).Value = Crypto.Encrypt(FirstName);
                        saveCmd.Parameters.Add("@LastName", SqlDbType.VarBinary).Value = Crypto.Encrypt(LastName);
                        saveCmd.Parameters.Add("@SecretQuestion", SqlDbType.VarBinary).Value = Crypto.Encrypt(SecretQuestion);
                        saveCmd.Parameters.Add("@SecretAnswer", SqlDbType.VarBinary).Value = Crypto.Encrypt(SecretAnswer);
                        saveCmd.Parameters.Add("@MobilePhone", SqlDbType.VarBinary).Value = Crypto.Encrypt(MobilePhone);
                        saveCmd.Parameters.Add("@ShortId", SqlDbType.VarBinary).Value = Crypto.Encrypt(ShortId);
                        saveCmd.Parameters.Add("@AdditionalInfo", SqlDbType.VarBinary).Value = Crypto.Encrypt(AdditionalInfo);

                        con.Open();

                        bool isRowsAffected = saveCmd.ExecuteNonQuery() > 0;
                        if (isRowsAffected)
                        {
                            Id = newId;
                        }
                    }
                }
                else
                {
                    ShowMessage.Error(Resources.SelectedServiceTypeIsExist);
                }
            }
            catch (Exception ex)
            {
                Logger.WriteLog(ex);
            }
        }

        public bool Update()
        {
            try
            {
                if (IsExist())
                {
                    using (SqlConnection con = CommonDb.GetBaseConection())
                    {
                        SqlCommand updCmd = new SqlCommand("AccountInfoUpdate", con);
                        updCmd.CommandType = CommandType.StoredProcedure;

                        updCmd.Parameters.Add("@Id", SqlDbType.UniqueIdentifier).Value = Id;
                        updCmd.Parameters.Add("@ServiceInfoId", SqlDbType.UniqueIdentifier).Value = ServiceInfoId;
                        updCmd.Parameters.Add("@Login", SqlDbType.VarBinary).Value = Crypto.Encrypt(Login);
                        updCmd.Parameters.Add("@Password", SqlDbType.VarBinary).Value = Crypto.Encrypt(Password);
                        updCmd.Parameters.Add("@Email", SqlDbType.VarBinary).Value = Crypto.Encrypt(Email);
                        updCmd.Parameters.Add("@FirstName", SqlDbType.VarBinary).Value = Crypto.Encrypt(FirstName);
                        updCmd.Parameters.Add("@LastName", SqlDbType.VarBinary).Value = Crypto.Encrypt(LastName);
                        updCmd.Parameters.Add("@SecretQuestion", SqlDbType.VarBinary).Value =
                            Crypto.Encrypt(SecretQuestion);
                        updCmd.Parameters.Add("@SecretAnswer", SqlDbType.VarBinary).Value = Crypto.Encrypt(SecretAnswer);
                        updCmd.Parameters.Add("@MobilePhone", SqlDbType.VarBinary).Value = Crypto.Encrypt(MobilePhone);
                        updCmd.Parameters.Add("@ShortId", SqlDbType.VarBinary).Value = Crypto.Encrypt(ShortId);
                        updCmd.Parameters.Add("@AdditionalInfo", SqlDbType.VarBinary).Value =
                            Crypto.Encrypt(AdditionalInfo);

                        con.Open();
                        return updCmd.ExecuteNonQuery() > 0;
                    }
                }
                return false;
            }
            catch (Exception ex)
            {
                Logger.WriteLog(ex);
                return false;
            }
        }

        public static bool Delete(Guid id)
        {
            try
            {
                using (SqlConnection con = CommonDb.GetBaseConection())
                {
                    SqlCommand delCmd = new SqlCommand("AccountInfoDelete", con);
                    delCmd.CommandType = CommandType.StoredProcedure;

                    delCmd.Parameters.Add("@Id", SqlDbType.UniqueIdentifier).Value = id;

                    con.Open();
                    return delCmd.ExecuteNonQuery() > 0;
                }
            }
            catch (Exception ex)
            {
                Logger.WriteLog(ex);
                return false;
            }
        }

        public static AccountInfo Select(Guid id)
        {
            try
            {
                using (SqlConnection con = CommonDb.GetBaseConection())
                {
                    SqlCommand getCmd = new SqlCommand("AccountInfoSelectById", con);
                    getCmd.CommandType = CommandType.StoredProcedure;

                    getCmd.Parameters.Add("@Id", SqlDbType.UniqueIdentifier).Value = id;

                    con.Open();
                    List<AccountInfo> cList = MapFrom(getCmd.ExecuteReader());

                    return cList != null ? cList.FirstOrDefault() : null;
                }
            }
            catch (Exception ex)
            {
                Logger.WriteLog(ex);
                return null;
            }
        }

        private bool IsExist()
        {
            try
            {
                using (SqlConnection con = CommonDb.GetBaseConection())
                {
                    SqlCommand getCmd = new SqlCommand("AccountInfoIsExist", con);
                    getCmd.CommandType = CommandType.StoredProcedure;

                    getCmd.Parameters.Add("@Id", SqlDbType.UniqueIdentifier).Value = Id != Guid.Empty ? (object)Id : DBNull.Value;
                    getCmd.Parameters.Add("@ServiceInfoId", SqlDbType.UniqueIdentifier).Value = ServiceInfoId;
                    getCmd.Parameters.Add("@Login", SqlDbType.VarBinary).Value = Crypto.Encrypt(Login);
                    getCmd.Parameters.Add("@Email", SqlDbType.VarBinary).Value = Crypto.Encrypt(Email);

                    con.Open();
                    return Convert.ToInt32(getCmd.ExecuteScalar()) > 0;
                }
            }
            catch (Exception ex)
            {
                Logger.WriteLog(ex);
                return true;
            }
        }

        private static List<AccountInfo> MapFrom(SqlDataReader dr)
        {
            try
            {
                if (dr != null && dr.HasRows)
                {
                    List<AccountInfo> acList = new List<AccountInfo>();
                    while (dr.Read())
                    {
                        AccountInfo wt = new AccountInfo
                        {
                            Id = Guid.Parse(dr["Id"].ToString()),
                            ServiceInfoId = Guid.Parse(dr["ServiceInfoId"].ToString()),
                            Login = Crypto.Decrypt((byte[])dr["Login"]),
                            Password = Crypto.Decrypt((byte[])dr["Password"]),
                            Email = Crypto.Decrypt((byte[])dr["Email"]),
                            FirstName = Crypto.Decrypt((byte[])dr["FirstName"]),
                            LastName = Crypto.Decrypt((byte[])dr["LastName"]),
                            SecretQuestion = Crypto.Decrypt((byte[])dr["SecretQuestion"]),
                            SecretAnswer = Crypto.Decrypt((byte[])dr["SecretAnswer"]),
                            MobilePhone = Crypto.Decrypt((byte[])dr["MobilePhone"]),
                            ShortId = Crypto.Decrypt((byte[])dr["ShortId"]),
                            AdditionalInfo = Crypto.Decrypt((byte[])dr["AdditionalInfo"]),
                            DateCreated = Convert.ToDateTime(dr["DateCreated"]),
                            Deleted = Convert.ToBoolean(dr["Deleted"]),
                        };

                        acList.Add(wt);
                    }
                    return acList;
                }
                return null;
            }
            catch (Exception ex)
            {
                Logger.WriteLog(ex);
                return null;
            }
        }
    }
}
